# app/middlewares/custom_middleware.py
from fastapi import FastAPI, Request, HTTPException
from typing import Callable, Optional, List
from functools import wraps
import time
import logging
from app.exceptions import AuthException

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class CustomMiddleware:
    """
    自定义中间件类，提供可选择性应用的路由中间件功能

    功能：
    1. 可以全局应用或选择性应用于特定路由
    2. 包含请求处理时间计算
    3. 简单的请求验证示例
    4. 可扩展的中间件功能

    使用方式：
    1. 全局应用：app.add_middleware(CustomMiddleware.global_middleware)
    2. 选择性应用：在路由上使用 @CustomMiddleware.apply_middleware()
    """

    @staticmethod
    async def global_middleware(request: Request, call_next: Callable):
        """
        全局中间件，会应用于所有路由

        参数:
        - request: FastAPI 请求对象
        - call_next: 下一个中间件或路由处理函数

        返回:
        - 响应对象
        """
        try:
            # 记录请求开始时间
            start_time = time.time()
            logger.info(f"全局中间件启动 | 路径: {request.url.path} | 方法: {request.method}")

            # 你可以在这里添加全局处理逻辑
            # 例如：验证请求头、记录日志等

            # 示例：检查请求头中是否包含特定信息
            if not request.headers.get("User-Agent"):
                raise AuthException(
                    detail="User-Agent header is missing",
                    code=400
                )
            # 调用下一个中间件或路由处理函数
            response = await call_next(request)
            # 计算处理时间
            process_time = time.time() - start_time
            response.headers["X-Process-Time"] = str(process_time)
            logger.info(f"全局中间件完成 | 耗时: {process_time:.2f}s")

            # 你可以在这里添加响应后处理逻辑
            # 例如：添加自定义响应头、记录响应日志等

            return response
        except Exception as e:
            # logger.error(f"中间件错误: {str(e)}")
            # 捕获未处理的异常也返回格式化响应
            return AuthException(
                detail=str(e),
                code=500,
                msg="服务器内部错误"
            ).to_response()

    @staticmethod
    def apply_middleware(
            exclude_paths: Optional[List[str]] = None,
            additional_checks: Optional[List[Callable]] = None
    ):
        """
        装饰器工厂函数，用于选择性应用中间件到特定路由

        参数:
        - exclude_paths: 要排除的路径列表 (即使应用了装饰器也不处理这些路径)
        - additional_checks: 额外的检查函数列表，每个函数接收request参数并返回bool

        返回:
        - 路由装饰器
        """

        def decorator(func):
            @wraps(func)
            async def wrapper(request: Request, *args, **kwargs):
                # 检查是否在排除路径中
                if exclude_paths and request.url.path in exclude_paths:
                    return await func(request, *args, **kwargs)

                # 记录请求开始时间
                start_time = time.time()

                # 执行额外的检查
                if additional_checks:
                    for check in additional_checks:
                        if not await check(request):
                            raise HTTPException(
                                status_code=400,
                                detail="Custom middleware check failed"
                            )

                # 示例检查：验证Content-Type
                if request.method in ["POST", "PUT", "PATCH"]:
                    content_type = request.headers.get("Content-Type", "")
                    if "application/json" not in content_type:
                        raise HTTPException(
                            status_code=415,
                            detail="Unsupported Media Type"
                        )

                # 调用路由处理函数
                response = await func(request, *args, **kwargs)

                # 计算处理时间
                process_time = time.time() - start_time
                response.headers["X-Process-Time"] = str(process_time)

                # 添加自定义响应头
                response.headers["X-Custom-Middleware"] = "Applied"

                return response

            return wrapper

        return decorator